home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / WASTE 1.3a5 / Demo / Source / WEDemoFiles.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-11  |  11.9 KB  |  482 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     File Handling
  4.  
  5.     Copyright © 1993-1997 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __WEDEMOAPP__
  13. #include "WEDemoIntf.h"
  14. #endif
  15.  
  16. #ifndef __FOLDERS__
  17. #include <Folders.h>
  18. #endif
  19.  
  20. #define    kFileNotOpened    -1
  21.  
  22. OSErr ReadTextFile ( const FSSpec * pFileSpec, WEReference we )
  23. {
  24.     SInt16 dataForkRefNum = kFileNotOpened;
  25.     SInt16 resForkRefNum = kFileNotOpened;
  26.     Handle hText = nil;
  27.     Handle hStyles = nil;
  28.     Handle hSoup = nil;
  29.     Handle hFontTable = nil;
  30.     Size textSize;
  31.     Boolean wasChanged = false;
  32.     OSErr err;
  33.  
  34.     //    open the data fork with read-only permission
  35.     if ((err = FSpOpenDF(pFileSpec, fsRdPerm, &dataForkRefNum)) != noErr)
  36.         goto cleanup;
  37.  
  38.     //    get data fork size
  39.     if ((err = GetEOF(dataForkRefNum, &textSize)) != noErr)
  40.         goto cleanup;
  41.  
  42.     //    set the position in the file from where to start reading
  43.     if ((err = SetFPos(dataForkRefNum, fsFromStart, 0L)) != noErr)
  44.         goto cleanup;
  45.  
  46.     //    try to allocate a handle that large, use temporary memory if available
  47.     if ((err = NewHandleTemp(textSize, &hText)) != noErr)
  48.         goto cleanup;
  49.  
  50.     //    read in the text
  51.     HLock(hText);
  52.     err = FSRead(dataForkRefNum, &textSize, *hText);
  53.     HUnlock(hText);
  54.     if (err != noErr)
  55.         goto cleanup;
  56.  
  57.     //    see if the file has a resource fork
  58.     //    FSpOpenResFile will return -1 if it fails
  59.     if ( ( resForkRefNum = FSpOpenResFile( pFileSpec, fsRdPerm ) ) != kFileNotOpened )
  60.     {
  61.         //    look for a style scrap resource (get the first one; the resource ID doesn't matter)
  62.         if ((hStyles = Get1IndResource(kTypeStyles, 1)) != nil)
  63.         {
  64.             DetachResource(hStyles);
  65.         }
  66.  
  67.         //    look for a soup resource as well
  68.         if ((hSoup = Get1IndResource(kTypeSoup, 1)) != nil)
  69.         {
  70.             DetachResource(hSoup);
  71.         }
  72.  
  73.         //    finally, look for a font table resource
  74.         if ((hFontTable = Get1IndResource(kTypeFontTable, 1)) != nil)
  75.         {
  76.             DetachResource(hFontTable);
  77.         }
  78.     }
  79.  
  80.     //    if both a style scrap and a font table were found,
  81.     //    re-map font IDs in the style scrap
  82.     if ((hStyles != nil) && (hFontTable != nil))
  83.     {
  84.         if ((WEUpdateFontTable(hFontTable, nil, &wasChanged) == noErr) && wasChanged)
  85.         {
  86.             WEUpdateStyleScrap((StScrpHandle) hStyles, hFontTable);
  87.         }
  88.     }
  89.  
  90.     //    insert the text into the WE record
  91.     HLock(hText);
  92.     if ((err = WEInsert(*hText, textSize, (StScrpHandle) hStyles, hSoup, we)) != noErr)
  93.         goto cleanup;
  94.  
  95.     //    set the insertion point at the beginning of the text
  96.     WESetSelection(0, 0, we);
  97.  
  98.     //    reset the WE instance modification count
  99.     WEResetModCount( we );
  100.  
  101. cleanup:
  102.     // display an alert box if anything went wrong
  103.     if (err != noErr)
  104.     {
  105.         ErrorAlert( err );
  106.     }
  107.  
  108.     ForgetHandle(&hText);
  109.     ForgetHandle(&hStyles);
  110.     ForgetHandle(&hSoup);
  111.     ForgetHandle(&hFontTable);
  112.  
  113.     if ( dataForkRefNum != kFileNotOpened )
  114.     {
  115.         FSClose(dataForkRefNum);
  116.         dataForkRefNum = kFileNotOpened;
  117.     }
  118.  
  119.     if ( resForkRefNum != kFileNotOpened )
  120.     {
  121.         CloseResFile(resForkRefNum);
  122.         resForkRefNum = kFileNotOpened;
  123.     }
  124.  
  125.     return err;
  126. }
  127.  
  128. // I added a bunch of other functionality to WriteTextFile(), mostly to show how to use
  129. // temp files, check for locked files, etc. ( all along Apple's recommended way of
  130. // doing things.  - JCD
  131.  
  132. OSErr WriteTextFile ( const FSSpec * pFileSpec, WEReference we )
  133. {
  134.     FInfo fileInfo ;
  135.     Size textSize ;
  136.     Boolean replacing ;
  137.     SInt16 dataForkRefNum = kFileNotOpened ;
  138.     SInt16 resForkRefNum = kFileNotOpened ;
  139.     Handle hText = nil ;
  140.     Handle hStyles = nil ;
  141.     Handle hSoup = nil ;
  142.     Handle hFontTable = nil;
  143.     UInt32 theTime ;
  144.     Str255 tempFileName ;
  145.     FSSpec tempFileSpec ;
  146.     SInt16 tempVRef ;        // volume reference # for the temp file
  147.     SInt32 tempDirID ;        // directory ID of the temp file
  148.     OSErr err ;
  149.  
  150.     //    will we be replacing an existing file?
  151.     err = FSpGetFInfo( pFileSpec, &fileInfo ) ;
  152.     if ( err == noErr )
  153.     {
  154.         replacing = true;
  155.     }
  156.     else if ( err == fnfErr )
  157.     {
  158.         replacing = false;
  159.     }
  160.     else
  161.     {
  162.         goto cleanup;
  163.     }
  164.  
  165.     // originally, Marco had it so that if the file already existed (replacing == true)
  166.     // then just can the original file and move along.  for the scope of this demo, that
  167.     // really is ok, but generally speaking, not the Apple-recommended way of doing things.
  168.     // since we know we're under (at least) System 7 (due to WASTE's need of it), we know
  169.     // we can use temporary files, so let us do so!
  170.  
  171.     // also, Marco didn't check for locked files (technically, if a file is locked from
  172.     // the Finder, you shouldn't be able to modify it).  let's check for that.
  173.  
  174.     // if the file currently exists (meaning it was saved at some time in the past, be it
  175.     // 5 minutes ago, or 5 days ago), there is a chance that it could be locked (from the
  176.     // Finder's "Get Info" window (or otherwise).  If the file is locked, you cannot
  177.     // save changes.  Therefore, if 'replacing' is true, we have to throw up a message
  178.     // saying that we can't do this, then exit.
  179.  
  180.     if ( replacing )
  181.     {
  182.         if ( ( err = FSpCheckObjectLock ( pFileSpec ) ) != noErr )
  183.         {
  184.             goto cleanup ;
  185.         }
  186.  
  187.         // create the temporary file name.  the name doesn't have to make sense, just
  188.         // be unique
  189.  
  190.         GetDateTime ( & theTime ) ;
  191.         NumToString ( theTime, tempFileName ) ;
  192.  
  193.         // find the temporary items folder on the file's volume; create it if necessary
  194.         // it is important that the temp folder (and the temp file) and the "original" target
  195.         // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
  196.         // and won't work
  197.  
  198.         if ( ( err = FindFolder ( pFileSpec -> vRefNum, kTemporaryFolderType, kCreateFolder, & tempVRef, & tempDirID ) ) != noErr )
  199.         {
  200.             goto cleanup ;
  201.         }
  202.  
  203.         // make an FSSpec for the temp file
  204.         err = FSMakeFSSpec ( tempVRef, tempDirID, tempFileName, & tempFileSpec ) ;
  205.         if ( (err != noErr) && (err != fnfErr ) )
  206.         {
  207.             goto cleanup ;
  208.         }
  209.     }
  210.  
  211.     //    create a new file.  if we're replacing, make a temp file.  if it's a
  212.     //  new file from the onset, just create the file
  213.  
  214.     // should we allow people to choose the file to create?  i.e. create a TEXT
  215.     // file or a ttro file?  if you'd like to do this, you'll want to find this
  216.     // info out when calling CustomPutFile() and pass that info to this function
  217.  
  218.     if ( replacing )
  219.     {
  220.         FSpCreateResFile( &tempFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  221.     }
  222.     else
  223.     {
  224.         FSpCreateResFile( pFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  225.     }
  226.  
  227.     if ((err = ResError()) != noErr)
  228.         goto cleanup;
  229.  
  230.     //  if replacing an old file, copy the old file information
  231.     if ( replacing )
  232.     {
  233.         if ( ( err = FSpSetFInfo( &tempFileSpec, &fileInfo ) ) != noErr )
  234.         {
  235.             goto cleanup;
  236.         }
  237.     }
  238.  
  239.     //    open the data fork for writing
  240.     if ( replacing )
  241.     {
  242.         err = FSpOpenDF( &tempFileSpec, fsRdWrPerm, &dataForkRefNum );
  243.     }
  244.     else
  245.     {
  246.         err = FSpOpenDF( pFileSpec, fsRdWrPerm, &dataForkRefNum );
  247.     }
  248.  
  249.     if ( err != noErr )
  250.     {
  251.         goto cleanup;
  252.     }
  253.  
  254.     //    set the end-of-file
  255.     if ( ( err = SetEOF( dataForkRefNum, 0 ) ) != noErr )
  256.     {
  257.         goto cleanup;
  258.     }
  259.  
  260.     //    set the position in the file to write from
  261.     if ( ( err = SetFPos( dataForkRefNum, fsFromStart, 0 ) ) != noErr )
  262.     {
  263.         goto cleanup;
  264.     }
  265.  
  266.     //    get the text handle from the WE instance
  267.     //    WEGetText returns the original handle, not a copy, so don't dispose of it!!
  268.     hText = WEGetText( we );
  269.     textSize = GetHandleSize( hText );
  270.  
  271.     //    write the text
  272.     HLock( hText );
  273.     err = FSWrite( dataForkRefNum, &textSize, *hText );
  274.     HUnlock( hText );
  275.  
  276.     if ( err != noErr )
  277.     {
  278.         goto cleanup;
  279.     }
  280.  
  281.     //    open the resource file for writing
  282.     if ( replacing )
  283.     {
  284.         resForkRefNum = FSpOpenResFile( &tempFileSpec, fsRdWrPerm );
  285.     }
  286.     else
  287.     {
  288.         resForkRefNum = FSpOpenResFile( pFileSpec, fsRdWrPerm );
  289.     }
  290.  
  291.     if ( ( err = ResError ( ) ) != noErr )
  292.     {
  293.         goto cleanup;
  294.     }
  295.  
  296.     //    allocate temporary handles to hold the style scrap, the soup
  297.     //    and the font table
  298.     //    try tapping temporary memory since WECopyRange() could get huge
  299.     if ( ( err = NewHandleTemp ( 0, & hStyles ) ) != noErr )
  300.     {
  301.         goto cleanup;
  302.     }
  303.     if ( ( err = NewHandleTemp ( 0, & hSoup ) ) != noErr )
  304.     {
  305.         goto cleanup;
  306.     }
  307.     if ( ( err = NewHandleTemp ( 0, & hFontTable ) ) != noErr )
  308.     {
  309.         goto cleanup ;
  310.     }
  311.  
  312.     //    create the style scrap and the soup
  313.     if ( ( err = WECopyRange ( 0, LONG_MAX, nil, ( StScrpHandle ) hStyles, hSoup, we ) ) != noErr )
  314.     {
  315.         goto cleanup ;
  316.     }
  317.  
  318.     //    create the font table
  319.     if ( ( err = WEBuildFontTable ( hFontTable, nil, we ) ) != noErr )
  320.     {
  321.         goto cleanup ;
  322.     }
  323.  
  324.     //    make them resource handles
  325.     AddResource ( hStyles, kTypeStyles, 128, "\p" ) ;
  326.     if ( ( err = ResError ( ) ) != noErr )
  327.     {
  328.         goto cleanup ;
  329.     }
  330.     AddResource ( hSoup, kTypeSoup, 128, "\p" ) ;
  331.     if ( ( err = ResError ( ) ) != noErr )
  332.     {
  333.         goto cleanup ;
  334.     }
  335.     AddResource ( hFontTable, kTypeFontTable, 128, "\p" ) ;
  336.     if ( ( err = ResError ( ) ) != noErr )
  337.     {
  338.         goto cleanup ;
  339.     }
  340.  
  341.     //    write them to the resource file
  342.     ChangedResource ( hStyles ) ;
  343.     WriteResource ( hStyles ) ;
  344.     if ( ( err = ResError ( ) ) != noErr )
  345.     {
  346.         goto cleanup ;
  347.     }
  348.     ChangedResource ( hSoup ) ;
  349.     WriteResource ( hSoup ) ;
  350.     if ( ( err = ResError ( ) ) != noErr )
  351.     {
  352.         goto cleanup ;
  353.     }
  354.     ChangedResource ( hFontTable ) ;
  355.     WriteResource ( hFontTable ) ;
  356.     if ( ( err = ResError ( ) ) != noErr )
  357.     {
  358.         goto cleanup ;
  359.     }
  360.  
  361.     //    "clean" this document by resetting the WE instance modification count
  362.     WEResetModCount ( we ) ;
  363.  
  364.     err = noErr;
  365.  
  366. cleanup:
  367.     // display an alert box if anything went wrong
  368.     if (err != noErr)
  369.     {
  370.         ErrorAlert( err );
  371.     }
  372.  
  373.     // remember, don't dispose the hText handle!
  374.     ForgetResource ( & hStyles ) ;
  375.     ForgetResource ( & hSoup ) ;
  376.     ForgetResource ( & hFontTable ) ;
  377.  
  378.     if ( dataForkRefNum != kFileNotOpened )
  379.     {
  380.         FSClose( dataForkRefNum ) ;
  381.         dataForkRefNum = kFileNotOpened ;
  382.     }
  383.  
  384.     if ( resForkRefNum != kFileNotOpened )
  385.     {
  386.         CloseResFile( resForkRefNum ) ;
  387.         resForkRefNum = kFileNotOpened ;
  388.     }
  389.  
  390.     if ( replacing )
  391.     {
  392.         // update the disk with any unwritten data
  393.  
  394.         FlushVol( nil, tempFileSpec.vRefNum );
  395.  
  396.         // since we were replacing an existing file, let's now swap the original
  397.         // and the temp file.  let's hear it for safe saves.
  398.  
  399.         if ( ( err = FSpExchangeFiles( &tempFileSpec, pFileSpec ) ) != noErr )
  400.         {
  401.             // handle the error
  402.             return err;
  403.         }
  404.  
  405.         // can the temp file since we don't need it anymore
  406.  
  407.         err = FSpDelete( &tempFileSpec );
  408.         if ( err != noErr )
  409.         {
  410.             // handle the error
  411.  
  412.             return err;
  413.         }
  414.     }
  415.  
  416.     // and update the disk with any unwritten data
  417.     FlushVol( nil, pFileSpec->vRefNum );
  418.  
  419.     return err;
  420. }
  421.  
  422.  
  423. /*    The following 2 functions (CheckObjectLock and FSpCheckObjectLock) were taken
  424.     from MoreFiles 1.2.1, a code sample from Apple's DTS.  Here's some info from
  425.     the MoreFiles readme:
  426.  
  427.         A collection of File Manager and related routines
  428.  
  429.         by Jim Luther, Apple Macintosh Developer Technical Support
  430.         with significant code contributions by Nitin Ganatra, Apple Macintosh Developer
  431.         Technical Support
  432.         MoreFile Reference is by Eric Soldan
  433.         Copyright © 1992-1994 Apple Computer, Inc.
  434.         All rights reserved.
  435.  
  436.     Frankly, this is one amazing repository of all sorts of file-related things.  I'd
  437.     check it out if you can. (should be, as of this writing, on ftp.info.apple.com
  438.     in like the /Apple.Support.Services/Developer_Support/ or something like that).
  439.  
  440.     thanx to Alex Rosen for answering my post on comp.sys.mac.programmer.help and pointing
  441.     out MoreFiles to me.
  442.  
  443.     WHAT DO THEY DO?  Oh duh...i should tell you huh?
  444.  
  445.     Both functions do the same thing:  check to see if the object is locked
  446.     (in this case, the object is a file).  This is using in WriteTextFile()
  447.     to prevent overwriting/deleting locked files.
  448.  
  449.     The only difference between these 2 functions are the arguments passed.
  450.     the first takes a vRefNum, dirID and a file name, the second takes an FSSpec
  451.     and then just calls the first based on the FSSpec (just makes for slighly
  452.     neater/readable code)
  453. */
  454.  
  455. pascal    OSErr    CheckObjectLock(SInt16 vRefNum, SInt32 dirID, StringPtr name)
  456. {
  457.     CInfoPBRec pb;
  458.     OSErr error;
  459.  
  460.     pb.hFileInfo.ioNamePtr = name;
  461.     pb.hFileInfo.ioVRefNum = vRefNum;
  462.     pb.hFileInfo.ioDirID = dirID;
  463.     pb.hFileInfo.ioFDirIndex = 0;    // use ioNamePtr and ioDirID
  464.     error = PBGetCatInfoSync(&pb);
  465.  
  466.     if ( error == noErr )
  467.     {
  468.         // check locked bit
  469.         if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
  470.             error = fLckdErr;
  471.     }
  472.     return ( error );
  473. }
  474.  
  475. /*****************************************************************************/
  476.  
  477. pascal    OSErr    FSpCheckObjectLock(const FSSpec *spec)
  478. {
  479.     return ( CheckObjectLock(spec->vRefNum, spec->parID, (StringPtr) spec->name) );
  480. }
  481.  
  482.